import java.util.PriorityQueue;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 86186
 * Date: 2023-09-18
 * Time: 11:29
 */
class MyTimerTask1 implements Comparable<MyTimerTask1>{
    //time 用来记录该任务执行的时间
    private long time;
    //runnable 用来记录该任务的具体内容
    private Runnable runnable;
    public MyTimerTask1(Runnable runnable, long delay) {
        this.runnable = runnable;
        this.time = (System.currentTimeMillis() + delay);
    }

    public long getTime() {
        return this.time;
    }

    public Runnable getRunnable() {
        return this.runnable;
    }

    @Override
    public int compareTo(MyTimerTask1 o) {
        //优先级队列每个节点必须是可比较的节点，所以我们在这里为 MytimerTask 提供一个比较方法
        return (int) (this.time - o.time);
    }
}

class Mytimer1 {
    //创建一个小根堆
    private PriorityQueue<MyTimerTask1> queue = new PriorityQueue<>();

    private static Object locker = new Object();
    public void schedule(Runnable runnable, long delay) {
        synchronized (locker) {
            queue.offer(new MyTimerTask1(runnable,delay));
            //在这里唤醒线程的目的有两个：
            //1.当堆为空的时候，如果在这个时候插入的话，可以唤醒线程
            //2.当堆不为空的时候，那么说明执行任务的线程处于等待状态，如果在这个时候加入一个任务，并且这个任务的执行时间先于堆顶任务
            //的执行时间，那么通过这个唤醒可以将该要加入的任务放在堆顶，使该任务为下一个要执行的任务
            locker.notify();
        }
    }

    public Mytimer1() {
        Thread t = new Thread(() -> {
           while (true) {
               try {
                   synchronized (locker) {
                       while (queue.isEmpty()) {
                           //当堆为空的时候，进入阻塞等待
                           locker.wait();
                       }
                       MyTimerTask1 task = queue.peek();
                       long time = task.getTime() - System.currentTimeMillis();
                       if (time <= 0) {
                           //说明时间已到，执行堆顶任务
                           task.getRunnable().run();
                           queue.poll();
                       }else {
                           //时间未到，该线程需等待time时间
                           locker.wait(time);
                       }
                   }
               } catch (Exception e) {
                   e.printStackTrace();
               }
           }
        });
        t.start();
    }
}
public class Demo2 {
    public static void main(String[] args) {
        Mytimer1 mytimer1 = new Mytimer1();
        mytimer1.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("炸弹爆炸");
            }
        },3000);
    }
}
